/*
 * objectaccess.h
 *
 *		对象访问钩子。
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 */

#ifndef OBJECTACCESS_H
#define OBJECTACCESS_H

/*
 * 对象访问钩子旨在在对 SQL 对象执行某些操作之前或之后被调用。
 * 这是为了安全或日志插件提供的基础设施。
 *
 * OAT_POST_CREATE 应在对象创建后立即调用。
 * 通常，这是在插入主要目录记录和相关依赖项之后完成的。
 *
 * OAT_DROP 应在对象删除之前调用；通常是 deleteOneObject()。
 * 它的参数封装在 ObjectAccessDrop 中。
 *
 * OAT_POST_ALTER 应在对象被更改后立即调用，
 * 但在命令计数器递增之前。使用钩子的扩展可以
 * 使用当前的 MVCC 快照获取元组的旧版本，
 * 并且可以使用 SnapshotSelf 获取元组的新版本。
 *
 * OAT_NAMESPACE_SEARCH 应在特定名称空间下进行对象名称查找之前调用。
 * 此事件相当于在默认访问控制机制下对模式的使用权限。
 *
 * OAT_FUNCTION_EXECUTE 应在函数执行之前调用。
 * 此事件几乎等同于对函数的执行权限，
 * 除了在创建或更改对象时检查执行权限的情况，
 * 因为 OAT_POST_CREATE 或 OAT_POST_ALTER 对于
 * 扩展跟踪这类检查已经足够。
 *
 * OAT_TRUNCATE 应在对象截断之前调用。此事件
 * 相当于在默认访问控制机制下对关系的截断权限。
 *
 * 在未来可能会添加其他类型。
 */
typedef enum ObjectAccessType
{
	OAT_POST_CREATE,
	OAT_DROP,
	OAT_POST_ALTER,
	OAT_NAMESPACE_SEARCH,
	OAT_FUNCTION_EXECUTE,
	OAT_TRUNCATE
} ObjectAccessType;

/*
 * OAT_POST_CREATE 事件的参数
 */
typedef struct
{
	/*
	 * 此标志通知扩展此创建的上下文是
	 * 由用户操作调用的，还是不是。例如，这将在
	 * 因类型变化而涉及内部事务的 Toast 表或索引时处理。
	 */
	bool		is_internal;
} ObjectAccessPostCreate;

/*
 * OAT_DROP 事件的参数
 */
typedef struct
{
	/*
	 * 标志通知扩展此删除的上下文。另见
	 * dependency.h 中的 PERFORM_DELETION_*
	 */
	int			dropflags;
} ObjectAccessDrop;

/*
 * OAT_POST_ALTER 事件的参数
 */
typedef struct
{
	/*
	 * 当系统目录有两个 ID 来标识一个
	 * 特定的目录元组时使用此标识符。仅在调用者
	 * 希望标识 pg_inherits、pg_db_role_setting 或
	 * pg_user_mapping 的条目时使用。在其他地方，
	 * 应设置 InvalidOid。
	 */
	Oid			auxiliary_id;

	/*
	 * 如果设置此标志，用户并未请求更改对象，
	 * 但我们出于某种内部原因仍然进行更改。
	 * 权限检查钩子可能希望跳过检查，例如，
	 * 当我们在 CLUSTER 期间更改临时堆的约束时。
	 */
	bool		is_internal;
} ObjectAccessPostAlter;

/*
 * OAT_NAMESPACE_SEARCH 的参数
 */
typedef struct
{
	/*
	 * 如果为 true，当权限未被允许搜索此模式时，钩子应报告错误。
	 */
	bool		ereport_on_violation;

	/*
	 * 本质上这是一个输出参数。核心代码应将
	 * 其初始化为 true，任何希望拒绝访问的扩展应将其重置
	 * 为 false。但是，扩展应谨慎，不应将 true
	 * 值存储在这里，以便在有多个扩展的情况下，只有
	 * 在所有扩展达成一致时才允许访问。
	 */
	bool		result;
} ObjectAccessNamespaceSearch;

/* 插件提供一个匹配一个或两个签名的钩子函数。 */
typedef void (*object_access_hook_type) (ObjectAccessType access,
										 Oid classId,
										 Oid objectId,
										 int subId,
										 void *arg);

typedef void (*object_access_hook_type_str) (ObjectAccessType access,
											 Oid classId,
											 const char *objectStr,
											 int subId,
											 void *arg);

/* 插件将此变量设置为适当的钩子函数。 */
extern PGDLLIMPORT object_access_hook_type object_access_hook;
extern PGDLLIMPORT object_access_hook_type_str object_access_hook_str;


/* 核心代码使用这些函数调用钩子（请参见下面的宏）。 */
extern void RunObjectPostCreateHook(Oid classId, Oid objectId, int subId,
									bool is_internal);
extern void RunObjectDropHook(Oid classId, Oid objectId, int subId,
							  int dropflags);
extern void RunObjectTruncateHook(Oid objectId);
extern void RunObjectPostAlterHook(Oid classId, Oid objectId, int subId,
								   Oid auxiliaryId, bool is_internal);
extern bool RunNamespaceSearchHook(Oid objectId, bool ereport_on_violation);
extern void RunFunctionExecuteHook(Oid objectId);

/* 字符串版本 */
extern void RunObjectPostCreateHookStr(Oid classId, const char *objectStr, int subId,
									   bool is_internal);
extern void RunObjectDropHookStr(Oid classId, const char *objectStr, int subId,
								 int dropflags);
extern void RunObjectTruncateHookStr(const char *objectStr);
extern void RunObjectPostAlterHookStr(Oid classId, const char *objectStr, int subId,
									  Oid auxiliaryId, bool is_internal);
extern bool RunNamespaceSearchHookStr(const char *objectStr, bool ereport_on_violation);
extern void RunFunctionExecuteHookStr(const char *objectStr);


/*
 * 以下宏是上面函数的封装；通常应使用这些宏来调用钩子，而不是直接调用上述函数。
 */

#define InvokeObjectPostCreateHook(classId,objectId,subId)			\
	InvokeObjectPostCreateHookArg((classId),(objectId),(subId),false)
#define InvokeObjectPostCreateHookArg(classId,objectId,subId,is_internal) \
	do {															\
		if (object_access_hook)										\
			RunObjectPostCreateHook((classId),(objectId),(subId),	\
									(is_internal));					\
	} while(0)

#define InvokeObjectDropHook(classId,objectId,subId)				\
	InvokeObjectDropHookArg((classId),(objectId),(subId),0)
#define InvokeObjectDropHookArg(classId,objectId,subId,dropflags)	\
	do {															\
		if (object_access_hook)										\
			RunObjectDropHook((classId),(objectId),(subId),			\
							  (dropflags));							\
	} while(0)

#define InvokeObjectTruncateHook(objectId)							\
	do {															\
		if (object_access_hook)										\
			RunObjectTruncateHook(objectId);						\
	} while(0)

#define InvokeObjectPostAlterHook(classId,objectId,subId)			\
	InvokeObjectPostAlterHookArg((classId),(objectId),(subId),		\
								 InvalidOid,false)
#define InvokeObjectPostAlterHookArg(classId,objectId,subId,		\
									 auxiliaryId,is_internal)		\
	do {															\
		if (object_access_hook)										\
			RunObjectPostAlterHook((classId),(objectId),(subId),	\
								   (auxiliaryId),(is_internal));	\
	} while(0)

#define InvokeNamespaceSearchHook(objectId, ereport_on_violation)	\
	(!object_access_hook											\
	 ? true															\
	 : RunNamespaceSearchHook((objectId), (ereport_on_violation)))

#define InvokeFunctionExecuteHook(objectId)		\
	do {										\
		if (object_access_hook)					\
			RunFunctionExecuteHook(objectId);	\
	} while(0)


#define InvokeObjectPostCreateHookStr(classId,objectName,subId)			\
	InvokeObjectPostCreateHookArgStr((classId),(objectName),(subId),false)
#define InvokeObjectPostCreateHookArgStr(classId,objectName,subId,is_internal) \
	do {															\
		if (object_access_hook_str)										\
			RunObjectPostCreateHookStr((classId),(objectName),(subId),	\
									(is_internal));					\
	} while(0)

#define InvokeObjectDropHookStr(classId,objectName,subId)				\
	InvokeObjectDropHookArgStr((classId),(objectName),(subId),0)
#define InvokeObjectDropHookArgStr(classId,objectName,subId,dropflags)	\
	do {															\
		if (object_access_hook_str)										\
			RunObjectDropHookStr((classId),(objectName),(subId),			\
							  (dropflags));							\
	} while(0)

#define InvokeObjectTruncateHookStr(objectName)							\
	do {															\
		if (object_access_hook_str)										\
			RunObjectTruncateHookStr(objectName);						\
	} while(0)

#define InvokeObjectPostAlterHookStr(classId,objectName,subId)			\
	InvokeObjectPostAlterHookArgStr((classId),(objectName),(subId),		\
								 InvalidOid,false)
#define InvokeObjectPostAlterHookArgStr(classId,objectName,subId,		\
									 auxiliaryId,is_internal)		\
	do {															\
		if (object_access_hook_str)										\
			RunObjectPostAlterHookStr((classId),(objectName),(subId),	\
								   (auxiliaryId),(is_internal));	\
	} while(0)

#define InvokeNamespaceSearchHookStr(objectName, ereport_on_violation)	\
	(!object_access_hook_str										\
	 ? true															\
	 : RunNamespaceSearchHookStr((objectName), (ereport_on_violation)))

#define InvokeFunctionExecuteHookStr(objectName)		\
	do {										\
		if (object_access_hook_str)					\
			RunFunctionExecuteHookStr(objectName);	\
	} while(0)


#endif							/* OBJECTACCESS_H */
